/** Java 1.3 AST Recognizer Grammar
 *
 * Author: (see java.g preamble)
 *
 * This grammar is in the PUBLIC DOMAIN
 */
class ExceptionScanner extends TreeParser;
		
options {
	importVocab = Java;		
}

{

    ///////////////////////////////////////////////////////////////////
    ////                         public methods                    ////

    // Usado no FlowGraph para resetar tudo
    public void reset() {
        _exceptionList = new HashMap();
	_arrayIndex = false;
    }
    
    public void setBBStatement(int bbstatement) {
        _bbStatement = bbstatement;
    }
    
    public Iterator exceptionIterator() {
        return _exceptionList.keySet().iterator();
    }

    ///////////////////////////////////////////////////////////////////
    ////                        private methods                    ////

    private void _addException(ExceptionEdgeData ex) {
        if(!_exceptionList.containsKey(ex)) {
	    _exceptionList.put(ex, null);
	}
    }

    ///////////////////////////////////////////////////////////////////
    ////                        private variables                  ////

    private HashMap _exceptionList;

    // Indica se foi processado um XXX.ident
    private boolean _fieldAccess;
        
	
    private boolean _arrayIndex;
	
    private int _bbStatement;
}


process 
 	:	stat |
                methodcall |
		#(FOR_INIT (variableDef | elist)?) |
	        #(FOR_CONDITION (expression)?) |
		#(FOR_ITERATOR (elist)?)
		
	;


typeSpec
	:	#(TYPE typeSpecArray)
	;

typeSpecArray
	:	#( ARRAY_DECLARATOR typeSpecArray )
	|	type
	;

type:	identifier
	|	builtInType
	;

builtInType
    :   "void"
    |   "boolean"
    |   "byte"
    |   "char"
    |   "short"
    |   "int"
    |   "float"
    |   "long"
    |   "double"
    ;

modifiers
	:	#( MODIFIERS (modifier)* )
	;

modifier
    :   "private"
    |   "public"
    |   "protected"
    |   "static"
    |   "transient"
    |   "final"
    |   "abstract"
    |   "native"
    |   "threadsafe"
    |   "synchronized"
    |   "const"
    |   "volatile"
	|	"strictfp"
    ;



methodDecl
	:	#(METHOD_DEF modifiers typeSpec methodHead)
	;

methodDef
	:	#(METHOD_DEF modifiers typeSpec methodHead (slist)?)
	;

variableDef
	:	#(VARIABLE_DEF modifiers typeSpec variableDeclarator varInitializer)
	;

parameterDef
	:	#(PARAMETER_DEF modifiers typeSpec IDENT )
	;

objectinitializer
	:	#(INSTANCE_INIT slist)
	;

variableDeclarator
	:	IDENT
	|	LBRACK variableDeclarator
	;

varInitializer
	:	#(ASSIGN initializer)
	|
	;

initializer
	:	expression
	|	arrayInitializer
	;

arrayInitializer
	:	#(ARRAY_INIT (initializer)*)
	;

methodHead
	:	IDENT #( PARAMETERS (parameterDef)* ) (throwsClause)?
	;

throwsClause
	:	#( "throws" (identifier)* )
	;

identifier   
	:	IDENT  
	|	#( DOT identifier IDENT ) 
	;

identifierStar
	:	IDENT
	|	#( DOT identifier (STAR|IDENT) )
	;

ctorSList
	:	#( SLIST (ctorCall)? (stat)* )
	;

slist
	:	#( SLIST (stat)* )
	;

stat:	/* typeDefinition */
		variableDef
	|	expression
	|	#(LABELED_STAT IDENT stat)
	|	#("if" expression stat (stat)? )
	|	#(	"for"
			#(FOR_INIT (variableDef | elist)?)
			#(FOR_CONDITION (expression)?)
			#(FOR_ITERATOR (elist)?)
			stat
		)
	|	#("while" expression stat)
	|	#("do" stat expression)
	|	#("break" (IDENT)? )
	|	#("continue" (IDENT)? )
	|	#("return" (expression)? )
	|	#("switch" expression (caseGroup)*)
	|	#("throw" expression)
	|	#("synchronized" expression stat)
	|	tryBlock
	|	slist // nested SLIST
	|	EMPTY_STAT
	;

caseGroup
	:	#(CASE_GROUP (#("case" expression) | "default")+ slist)
	;

tryBlock
	:	#( "try" slist (handler)* (#("finally" slist))? )
	;

handler
	:	#( "catch" parameterDef slist )
	;

elist
	:	#( ELIST (expression)* )
	;

expression
	:	#(EXPR expr)
	;

expr:	#(QUESTION expr expr expr) 
	|	#(ASSIGN { _arrayIndex = false; } expr {
	          
		      if(_arrayIndex) {

		          _addException(new ExceptionEdgeData(
			        ExceptionEdgeData.ARRAY_STORE,
			        _bbStatement, null,			     
			        ArrayStoreException.class));

			  _arrayIndex = false;
		      }
	 
	          } expr)
	|	#(PLUS_ASSIGN expr expr)
	|	#(MINUS_ASSIGN expr expr)
	|	#(STAR_ASSIGN expr expr)
	|	#(DIV_ASSIGN expr expr)
	|	#(MOD_ASSIGN expr expr)
	|	#(SR_ASSIGN expr expr)
	|	#(BSR_ASSIGN expr expr)
	|	#(SL_ASSIGN expr expr)
	|	#(BAND_ASSIGN expr expr)
	|	#(BXOR_ASSIGN expr expr)
	|	#(BOR_ASSIGN expr expr)
	|	#(LOR expr expr)
	|	#(LAND expr expr)
	|	#(BOR expr expr)
	|	#(BXOR expr expr)
	|	#(BAND expr expr)
	|	#(NOT_EQUAL expr expr)
	|	#(EQUAL expr expr)
	|	#(LT expr expr)
	|	#(GT expr expr)
	|	#(LE expr expr)
	|	#(GE expr expr)
	|	#(SL expr expr)
	|	#(SR expr expr)
	|	#(BSR expr expr)
	|	#(PLUS expr {
	
 	             _addException(new ExceptionEdgeData(
 	 		    ExceptionEdgeData.NO_MEMORY, 
			    _bbStatement, null,
			    OutOfMemoryError.class));
	          
		  }
	
	          expr )
		  
	|	#(MINUS expr expr)

	|	#(DIV expr expr {

 	             _addException(new ExceptionEdgeData(
 	 		    ExceptionEdgeData.DIV, 
			    _bbStatement, null,
			    ArithmeticException.class));	
	         })

	|	#(MOD expr expr {

 	             _addException(new ExceptionEdgeData(
 	 		    ExceptionEdgeData.REM, 
			    _bbStatement, null,
			    ArithmeticException.class));		        
		})

	|	#(STAR expr expr)
	|	#(INC expr)
	|	#(DEC expr)
	|	#(POST_INC expr)
	|	#(POST_DEC expr)
	|	#(BNOT expr)
	|	#(LNOT expr)
	|	#("instanceof" expr expr)
	|	#(UNARY_MINUS expr)
	|	#(UNARY_PLUS expr)
	|	primaryExpression
	;

primaryExpression
    :   IDENT

    |   #(	DOT
			(	expr
				(	IDENT { 
				           _fieldAccess = true; 
					   
					   _addException(new ExceptionEdgeData(
			                        ExceptionEdgeData.FIELD_ACCESS,
			                        _bbStatement, null,			     
			                         NullPointerException.class));
				         
					}
				
				|	arrayIndex
				
				|	"this"
				
				|	"class"
				
				|	#( "new" {		 
				 
				            _addException(new ExceptionEdgeData(
 	 		                        ExceptionEdgeData.NO_MEMORY, 
			                        _bbStatement, null,
			                        OutOfMemoryError.class));
				            }
				         
					    IDENT elist )
				
				|   "super"
				
				)

			|	#(ARRAY_DECLARATOR typeSpecArray)
			
			|	builtInType ("class")?

			)
		)
	|	arrayIndex
	
	|	methodcall

	|	#(TYPECAST {

	              	_addException(new ExceptionEdgeData(
 	 		    ExceptionEdgeData.CAST, 
			    _bbStatement, null,
			    ClassCastException.class));
	
	          } typeSpec expr)
	
	|   newExpression {

	      _addException(new ExceptionEdgeData(
 	          ExceptionEdgeData.NO_MEMORY, _bbStatement, null,			     
	          OutOfMemoryError.class));

            }
	
	|   constant

    |   "super"

    |   "true"

    |   "false"

    |   "this"

    |   "null"

	|	typeSpec // type name used with instanceof
	;


methodcall:
		#(METHOD_CALL 
	            // vai pegar o ultimo field
	            { _fieldAccess = false; } 

		    primaryExpression 

		    {
		       if(_fieldAccess) {
		           _addException(new ExceptionEdgeData(
			       ExceptionEdgeData.MC_FIELD, 
			       _bbStatement, null,			     
			       NullPointerException.class));	       
		       }
		    }
		    
		    elist )

	;

ctorCall
	:	#( CTOR_CALL elist )
	|	#( SUPER_CTOR_CALL
			(	elist
			|	primaryExpression elist
			)
		 )
	;

arrayIndex
	:	#(INDEX_OP primaryExpression {

	             _addException(new ExceptionEdgeData(
			       ExceptionEdgeData.ARRAY_ACCESS, 
			       _bbStatement, null,			     
			       NullPointerException.class));
			       
	             _addException(new ExceptionEdgeData(
			       ExceptionEdgeData.INDEX_BOUNDS, 
			       _bbStatement, null,			     
			       ArrayIndexOutOfBoundsException.class));
	
	          } expression { _arrayIndex = true; } )
	;

constant
    :   NUM_INT
    |   CHAR_LITERAL
    |   STRING_LITERAL 
    |   NUM_FLOAT
    |   NUM_DOUBLE
    |   NUM_LONG
    ;

newExpression
	:	#(	"new" type

			(	newArrayDeclarator {

 	 		            _addException(new ExceptionEdgeData(
			                ExceptionEdgeData.NEG_ARRAY, 
			                _bbStatement, null,			     
			                NegativeArraySizeException.class));			
					            			
			        }
				 (arrayInitializer)?

			|	elist /*(objBlock)? */
			)
		)
			
	;

newArrayDeclarator
	:	#( ARRAY_DECLARATOR (newArrayDeclarator)? (expression)? )
	;
